Add code to handle N-components
authorØyvind Kolås <pippin@gimp.org>
Sun, 27 Jun 2010 23:42:02 +0000 (00:42 +0100)
committerØyvind Kolås <pippin@gimp.org>
Mon, 28 Jun 2010 00:48:14 +0000 (01:48 +0100)
Added a new API call, babl_format_n (). This allows constructing a babl
format with an arbitrary number of components all of the same type. At
the moment. The model used for such formats is "Y", at the moment
conversions are only well defined for such formats to other n-component
formats with the same number of components.

babl/babl-classes.h
babl/babl-fish-reference.c
babl/babl-format.c
babl/babl.h
tests/Makefile.am
tests/n_components.c [new file with mode: 0644]

index 0427c3059cdd4fd242fc3336ad61d0ef955294d0..fa25c4e32e77f1dd7d391b4db5bd26351616ced3 100644 (file)
@@ -67,7 +67,7 @@ enum {
 
 
 /* This union can be used for convenient access to any field without
- * the need to case if the variable already is of the type Babl*
+ * the need to cast if the variable already is of the type Babl*
  */
 typedef union _Babl
 {
index 0b1cc27f7b16a3e836ab0c1cadad59ed63a78c52..5fbc8378f3e052199bf0acdb9b167b3354109c7b 100644 (file)
@@ -201,6 +201,79 @@ convert_from_double (BablFormat *destination_fmt,
 }
 
 
+static void
+ncomponent_convert_to_double (BablFormat *source_fmt,
+                              BablImage  *source,
+                              char       *source_buf,
+                              char       *source_double_buf,
+                              int         n)
+{
+  BablImage *src_img;
+  BablImage *dst_img;
+
+  src_img = (BablImage *) babl_image_new (
+    babl_component_from_id (BABL_LUMINANCE), NULL, 1, 0, NULL);
+  dst_img = (BablImage *) babl_image_new (
+    babl_component_from_id (BABL_LUMINANCE), NULL, 1, 0, NULL);
+
+  dst_img->type[0]  = (BablType *) babl_type_from_id (BABL_DOUBLE);
+  dst_img->pitch[0] = (dst_img->type[0]->bits / 8);
+  dst_img->stride[0] = 0;
+
+  src_img->data[0]   = source_buf;
+  src_img->type[0] = source_fmt->type[0];
+  src_img->pitch[0] = source_fmt->type[0]->bits / 8;
+  src_img->stride[0] = 0;
+
+  dst_img->data[0] = source_double_buf;
+
+  babl_process (
+    assert_conversion_find (src_img->type[0], dst_img->type[0]),
+    src_img, dst_img,
+    n * source_fmt->components);
+  babl_free (src_img);
+  babl_free (dst_img);
+}
+
+static void
+ncomponent_convert_from_double (BablFormat *destination_fmt,
+                                char       *destination_double_buf,
+                                BablImage  *destination,
+                                char       *destination_buf,
+                                int         n)
+{
+  BablImage *src_img;
+  BablImage *dst_img;
+
+  src_img = (BablImage *) babl_image_new (
+    babl_component_from_id (BABL_LUMINANCE), NULL, 1, 0, NULL);
+  dst_img = (BablImage *) babl_image_new (
+    babl_component_from_id (BABL_LUMINANCE), NULL, 1, 0, NULL);
+
+  src_img->type[0]   = (BablType *) babl_type_from_id (BABL_DOUBLE);
+  src_img->pitch[0]  = (src_img->type[0]->bits / 8);
+  src_img->stride[0] = 0;
+
+  dst_img->data[0]  = destination_buf;
+  dst_img->type[0]  = (BablType *) babl_type_from_id (BABL_DOUBLE);
+  dst_img->pitch[0] = destination_fmt->type[0]->bits/8;
+  dst_img->stride[0] = 0;
+
+  dst_img->type[0] = destination_fmt->type[0];
+  src_img->data[0] = destination_double_buf;
+
+  babl_process (
+    assert_conversion_find (src_img->type[0], dst_img->type[0]),
+    src_img, dst_img,
+    n * destination_fmt->components);
+
+  dst_img->data[0] += dst_img->type[0]->bits / 8;
+  babl_free (src_img);
+  babl_free (dst_img);
+}
+
+
+
 static int
 process_same_model (Babl      *babl,
                     BablImage *source,
@@ -217,24 +290,51 @@ process_same_model (Babl      *babl,
     }
 
   double_buf = babl_malloc (sizeof (double) * n *
-                            BABL (babl->fish.source)->format.model->components);
+                            BABL (babl->fish.source)->format.components);
 
-  convert_to_double (
-    (BablFormat *) BABL (babl->fish.source),
-    BABL_IS_BABL (source) ? source : NULL,
-    BABL_IS_BABL (source) ? NULL : (char *) source,
-    double_buf,
-    n
-  );
+  if (
+      (BABL (babl->fish.source)->format.components ==
+       BABL (babl->fish.destination)->format.components)
+      && (BABL (babl->fish.source)->format.model->components !=
+          BABL (babl->fish.source)->format.components))
+    {
+      /* FIXME: should recursively invoke babl and look up an appropriate fish
+       * for the conversion and multiply n by the number of components.
+       */
+      ncomponent_convert_to_double (
+        (BablFormat *) BABL (babl->fish.source),
+        BABL_IS_BABL (source) ? source : NULL,
+        BABL_IS_BABL (source) ? NULL : (char *) source,
+        double_buf,
+        n
+      );
 
-  convert_from_double (
-    (BablFormat *) BABL (babl->fish.destination),
-    double_buf,
-    BABL_IS_BABL (destination) ? destination : NULL,
-    BABL_IS_BABL (destination) ? NULL : (char *) destination,
-    n
-  );
+      ncomponent_convert_from_double (
+        (BablFormat *) BABL (babl->fish.destination),
+        double_buf,
+        BABL_IS_BABL (destination) ? destination : NULL,
+        BABL_IS_BABL (destination) ? NULL : (char *) destination,
+        n
+      );
+    }
+  else
+    {
+      convert_to_double (
+        (BablFormat *) BABL (babl->fish.source),
+        BABL_IS_BABL (source) ? source : NULL,
+        BABL_IS_BABL (source) ? NULL : (char *) source,
+        double_buf,
+        n
+      );
 
+      convert_from_double (
+        (BablFormat *) BABL (babl->fish.destination),
+        double_buf,
+        BABL_IS_BABL (destination) ? destination : NULL,
+        BABL_IS_BABL (destination) ? NULL : (char *) destination,
+        n
+      );
+    }
   babl_free (double_buf);
   return 0;
 }
@@ -252,6 +352,7 @@ babl_fish_reference_process (Babl      *babl,
   Babl *rgba_image;
   Babl *destination_image;
 
+
   if (BABL (babl->fish.source)->format.model ==
       BABL (babl->fish.destination)->format.model)
     return process_same_model (babl, source, destination, n);
index 4c75d3cf684b58162b0fcedae50f8de476bacce5..186d15a3e5e387a513549853bd6238b0446672d6 100644 (file)
@@ -116,7 +116,6 @@ format_new (const char     *name,
 }
 
 
-
 static char *
 create_name (BablModel      *model,
              int             components,
@@ -185,6 +184,58 @@ create_name (BablModel      *model,
   return babl_strdup (buf);
 }
 
+
+static char *
+ncomponents_create_name (Babl *type,
+                         int   components)
+{
+  char buf[512];
+  sprintf (buf, "%s[%i] ", type->instance.name, components);
+  return babl_strdup (buf);
+}
+
+Babl *
+babl_format_n (Babl *btype,
+               int   components)
+{
+  int            i;
+  Babl          *babl;
+  int            id         = 0;
+  int            planar     = 0;
+  BablModel     *model      = (BablModel *)babl_model ("Y");
+  BablComponent *component [components];
+  BablSampling  *sampling  [components];
+  BablType      *type      [components];
+  char          *name       = NULL;
+
+  for (i = 0; i<components; i++)
+    {
+      component[i] = model->component[0];
+      type[i] = &btype->type;
+      sampling[i] = (BablSampling *) babl_sampling (1, 1);
+    }
+
+  name = ncomponents_create_name (btype, components);
+  babl = babl_db_exist (db, id, name);
+  if (babl)
+    {
+      /* There is an instance already registered by the required id/name,
+       * returning the preexistent one instead.
+       */
+      babl_free (name);
+      return babl;
+    }
+
+  babl = format_new (name,
+                     id,
+                     planar, components, model,
+                     component, sampling, type);
+
+  babl_db_insert (db, babl);
+  babl_free (name);
+  return babl;
+}
+
 Babl *
 babl_format_new (void *first_arg,
                  ...)
@@ -322,9 +373,6 @@ babl_format_new (void *first_arg,
                      planar, components, model,
                      component, sampling, type);
 
-  /* Since there is not an already registered instance by the required
-   * id/name, inserting newly created class into database.
-   */
   babl_db_insert (db, babl);
   babl_free (name);
   return babl;
index 44276a497e7410f49192b85b006a4c037987bf48..1ad2ea79b16db2d31b191598871e6a7f3cbce3ce 100644 (file)
@@ -153,7 +153,7 @@ Babl * babl_model_new      (void *first_arg,
                             ...) BABL_ARG_NULL_TERMINATED;
 
 /**
- * Defines a new color format in babl. Provided BablType and|or
+ * Defines a new pixel format in babl. Provided BablType and|or
  * BablSampling is valid for the following components as well. If no
  * name is provided a (long) descriptive name is used.
  *
@@ -172,6 +172,16 @@ Babl * babl_model_new      (void *first_arg,
 Babl * babl_format_new     (void *first_arg,
                             ...) BABL_ARG_NULL_TERMINATED;
 
+/*
+ * Defines a new pixel format in babl. With the specified data storage
+ * type and the given number of components. At the moment behavior of 
+ * conversions are only well defined to other babl_format_n derived formats
+ * with the same number of components.
+ */
+Babl *
+babl_format_n (Babl *type,
+               int   components);
+
 /**
  * Defines a new conversion between either two formats, two models or
  * two types in babl.
index 9fa34e286e994d16cfd7b494d9ad1f7b896cb0fe..e8fdd1d726c9d65df3941e917c69fac92f512691 100644 (file)
@@ -10,6 +10,7 @@ TESTS =                               \
        sanity                  \
        babl_class_name         \
        types                   \
+       n_components            \
        models                  \
        $(CONCURRENCY_STRESS_TEST)
 
diff --git a/tests/n_components.c b/tests/n_components.c
new file mode 100644 (file)
index 0000000..0cfeb11
--- /dev/null
@@ -0,0 +1,116 @@
+/* babl - dynamically extendable universal pixel conversion library.
+ * Copyright (C) 2005, Øyvind Kolås.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "config.h"
+#include <math.h>
+#include "babl-internal.h"
+
+#define PIXELS       7
+#define COMPONENTS   2048
+#define TOLERANCE    0
+
+float source_buf [PIXELS * COMPONENTS] =
+{
+   0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 
+   0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 
+   0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 
+   0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 
+   0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 
+   0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 
+   0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 
+   0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 
+   0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 
+   0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 
+   0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 
+   0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 
+   0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 
+   0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 
+   0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 
+   0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 
+  /* the rest of the input buffer is nulls */
+}; 
+
+unsigned char reference_buf [PIXELS * COMPONENTS] =
+{ 
+  26, 51, 77, 102, 128, 153, 26, 51, 77, 102, 128, 153,
+  26, 51, 77, 102, 128, 153, 26, 51, 77, 102, 128, 153,
+  26, 51, 77, 102, 128, 153, 26, 51, 77, 102, 128, 153,
+  26, 51, 77, 102, 128, 153, 26, 51, 77, 102, 128, 153,
+  26, 51, 77, 102, 128, 153, 26, 51, 77, 102, 128, 153,
+  26, 51, 77, 102, 128, 153, 26, 51, 77, 102, 128, 153,
+  26, 51, 77, 102, 128, 153, 26, 51, 77, 102, 128, 153,
+  26, 51, 77, 102, 128, 153, 26, 51, 77, 102, 128, 153,
+  26, 51, 77, 102, 128, 153, 26, 51, 77, 102, 128, 153,
+  26, 51, 77, 102, 128, 153, 26, 51, 77, 102, 128, 153,
+  26, 51, 77, 102, 128, 153, 26, 51, 77, 102, 128, 153,
+  26, 51, 77, 102, 128, 153, 26, 51, 77, 102, 128, 153,
+  26, 51, 77, 102, 128, 153, 26, 51, 77, 102, 128, 153,
+  26, 51, 77, 102, 128, 153, 26, 51, 77, 102, 128, 153,
+  26, 51, 77, 102, 128, 153, 26, 51, 77, 102, 128, 153,
+  26, 51, 77, 102, 128, 153, 26, 51, 77, 102, 128, 153,
+  /* the rest of the reference buffer is nulls */
+};
+
+unsigned char destination_buf [PIXELS * COMPONENTS];
+
+static int
+test (void)
+{
+  int   components;
+  int   OK = 1;
+
+  for (components = 1; components < 2048; components ++)
+  {
+    Babl *fish;
+    Babl *src_fmt;
+    Babl *dst_fmt;
+    int   i;
+
+    src_fmt = babl_format_n (babl_type ("float"), components);
+    dst_fmt = babl_format_n (babl_type ("u8"), components);
+
+    fish = babl_fish (src_fmt, dst_fmt);
+
+    babl_process (fish, source_buf, destination_buf, PIXELS);
+
+    for (i = 0; i < PIXELS * components; i++)
+      {
+        if (abs (destination_buf[i] - reference_buf[i]) > TOLERANCE)
+          {
+            babl_log ("%i-components, pixel %i component %i is %i should be %i",
+                      components, i / components, i % components, destination_buf[i], reference_buf[i]);
+            OK = 0;
+          }
+      }
+  }
+  if (!OK)
+    return -1;
+  return 0;
+}
+
+int
+main (int    argc,
+      char **argv)
+{
+  babl_init ();
+  if (test ())
+    return -1;
+  babl_exit ();
+  return 0;
+}